home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / lfs / lfsFileIndex.c < prev    next >
C/C++ Source or Header  |  1991-08-08  |  28KB  |  871 lines

  1. /* 
  2.  * lfsFileIndex.c --
  3.  *
  4.  *    Routines to allow moving through a files block pointers.  The method
  5.  *    of using these routines is the following:
  6.  *
  7.  *        1) Call LfsFile_GetIndex to get the index of a specified block
  8.  *                of a specified file.
  9.  *        2) Call LfsFile_SetIndex to set the index of a specified block
  10.  *                of a specified file.
  11.  *        2) Call LfsFile_TruncIndex to truncate the index of a specified
  12.  *                file to the specified block number.
  13.  *
  14.  *
  15.  *    The data structure operated on is the disk map kept in the disk
  16.  *    file descriptor (LfsFileDescriptor).  This has 10 direct block pointers,
  17.  *    then a singly indirect block full of direct block pointers,
  18.  *    then a doubly indirect block full of singly indirect pointers.
  19.  *    The triple indirect block pointer is not implemented, limiting
  20.  *    the file size to 40K + 4Meg + 4Gigabytes.
  21.  *
  22.  * Copyright 1987 Regents of the University of California
  23.  * All rights reserved.
  24.  * Permission to use, copy, modify, and distribute this
  25.  * software and its documentation for any purpose and without
  26.  * fee is hereby granted, provided that the above copyright
  27.  * notice appear in all copies.  The University of California
  28.  * makes no representations about the suitability of this
  29.  * software for any purpose.  It is provided "as is" without
  30.  * express or implied warranty.
  31.  */
  32.  
  33. #ifndef lint
  34. static char rcsid[] = "$Header: /sprite/src/kernel/lfs/RCS/lfsFileIndex.c,v 1.7 91/08/08 17:46:16 mendel Exp $ SPRITE (Berkeley)";
  35. #endif not lint
  36.  
  37. #include "sprite.h"
  38. #include "fs.h"
  39. #include "lfs.h"
  40. #include "lfsInt.h"
  41. #include "fsutil.h"
  42. #include "fscache.h"
  43. #include "fsdm.h"
  44.  
  45. /*
  46.  * Index operation type for AccessBlock routine.
  47.  */
  48. enum IndexOp { GET_ADDR, SET_ADDR, GROW_ADDR};
  49.  
  50. static ReturnStatus GrowBlock _ARGS_((Lfs *lfsPtr, 
  51.         Fsio_FileIOHandle *handlePtr, int blockNum, int blockSize,
  52.         LfsDiskAddr diskAddress, int cacheFlags));
  53.  
  54. static ReturnStatus AccessBlock _ARGS_((enum IndexOp op, Lfs *lfsPtr, 
  55.         Fsio_FileIOHandle *handlePtr, int blockNum, int blockSize,
  56.         int cacheFlags, LfsDiskAddr *diskAddressPtr));
  57. static ReturnStatus DeleteIndirectBlock _ARGS_((Lfs *lfsPtr, 
  58.         Fsio_FileIOHandle *handlePtr, int virtualBlockNum,
  59.         LfsDiskAddr *diskAddrPtr,
  60.         int startBlockNum, int lastBlockNum, int step, 
  61.         int lastByteBlock));
  62.  
  63.  
  64. /*
  65.  *----------------------------------------------------------------------
  66.  *
  67.  * LfsFile_GetIndex --
  68.  *
  69.  *    Return the disk address of the specified block of a specified file.
  70.  *
  71.  * Results:
  72.  *    A status indicating whether there was sufficient space to allocate
  73.  *    indirect blocks.
  74.  *
  75.  * Side effects:
  76.  *
  77.  *----------------------------------------------------------------------
  78.  */
  79.  
  80. ReturnStatus
  81. LfsFile_GetIndex(handlePtr, blockNum, cacheFlags, diskAddressPtr)
  82.     Fsio_FileIOHandle    *handlePtr;   /* Handle for file that are 
  83.                           * interest in. */
  84.     int                blockNum;    /* Block number of interest. */
  85.     int        cacheFlags;         /* FSCACHE_CANT_BLOCK,FSCACHE_DONT_BLOCK.*/
  86.     LfsDiskAddr *diskAddressPtr;      /* Disk address returned. */
  87. {
  88.     Lfs                *lfsPtr;
  89.     Fsdm_Domain            *domainPtr;
  90.     ReturnStatus        status;
  91.  
  92.     domainPtr = Fsdm_DomainFetch(handlePtr->hdr.fileID.major, TRUE);
  93.     if (domainPtr == (Fsdm_Domain *)NIL) {
  94.     return(FS_DOMAIN_UNAVAILABLE);
  95.     }
  96.     lfsPtr = LfsFromDomainPtr(domainPtr);
  97.     LFS_STATS_INC(lfsPtr->stats.index.get);
  98.     status = AccessBlock(GET_ADDR, lfsPtr, handlePtr, blockNum, 0, cacheFlags,
  99.                 diskAddressPtr);
  100.     Fsdm_DomainRelease(handlePtr->hdr.fileID.major);
  101.     return status;
  102. }
  103.  
  104. /*
  105.  *----------------------------------------------------------------------
  106.  *
  107.  * LfsFile_SetIndex --
  108.  *
  109.  *    Set the disk address of the specified block of a specified file.
  110.  *
  111.  * Results:
  112.  *    SUCCESS if operation worked. FS_WOULD_BLOCK if operation would
  113.  *    block and cantBlock argument set.
  114.  *
  115.  * Side effects:
  116.  *
  117.  *----------------------------------------------------------------------
  118.  */
  119.  
  120. ReturnStatus
  121. LfsFile_SetIndex(handlePtr, blockNum, blockSize, cacheFlags, diskAddress)
  122.     Fsio_FileIOHandle          *handlePtr;    /* Handle for file that are 
  123.                           * interest in. */
  124.     int            blockNum;          /* Block number of interest. */
  125.     int            blockSize;         /* Size of block in bytes. */
  126.     int        cacheFlags;         /* FSCACHE_CANT_BLOCK,FSCACHE_DONT_BLOCK.*/
  127.     LfsDiskAddr     diskAddress;              /* Disk address of block. */
  128. {
  129.     Lfs                *lfsPtr;
  130.     Fsdm_Domain            *domainPtr;
  131.     ReturnStatus        status;
  132.  
  133.     domainPtr = Fsdm_DomainFetch(handlePtr->hdr.fileID.major, TRUE);
  134.     if (domainPtr == (Fsdm_Domain *)NIL) {
  135.     return(FS_DOMAIN_UNAVAILABLE);
  136.     }
  137.     lfsPtr = LfsFromDomainPtr(domainPtr);
  138.     LFS_STATS_INC(lfsPtr->stats.index.set);
  139.     /*
  140.      * Checking. 
  141.      */
  142. #ifdef ERROR_CHECK
  143.    if (!LfsIsNilDiskAddr(diskAddress)) { 
  144.         int segNo;
  145.     segNo = LfsDiskAddrToSegmentNum(lfsPtr, diskAddress);
  146.     if (!LfsValidSegmentNum(lfsPtr,segNo)) {
  147.         panic("LfsFile_SetIndex: bad segment number.\n");
  148.     }
  149.     }
  150. #endif
  151.     status = AccessBlock(SET_ADDR, lfsPtr, handlePtr, blockNum, blockSize,
  152.         cacheFlags, &diskAddress);
  153.     Fsdm_DomainRelease(handlePtr->hdr.fileID.major);
  154.     return status;
  155. }
  156.  
  157. /*
  158.  *----------------------------------------------------------------------
  159.  *
  160.  * GrowBlock --
  161.  *
  162.  *    Grow the specified block to take occupy more space.
  163.  *
  164.  * Results:
  165.  *    SUCCESS if operation worked ok.
  166.  *    FS_WOULD_BLOCK if operation would block an cantBlock set.
  167.  *
  168.  * Side effects:
  169.  *    The block may be fetched into the cache and marked as
  170.  *    modified to get to be written to the log again.
  171.  *
  172.  *----------------------------------------------------------------------
  173.  */
  174. static ReturnStatus
  175. GrowBlock(lfsPtr, handlePtr, blockNum, growthSize, diskAddr, cacheFlags)
  176.     Lfs        *lfsPtr;             /* File system of file. */
  177.     Fsio_FileIOHandle          *handlePtr;    /* Handle for file that are 
  178.                           * interest in. */
  179.     int        blockNum;             /* Block number of file. */
  180.     int        growthSize;        /* Block growth size. */
  181.     LfsDiskAddr diskAddr;            /* Disk address of block. */
  182.     int        cacheFlags;         /* FSCACHE_CANT_BLOCK,FSCACHE_DONT_BLOCK.*/
  183. {
  184.     Fsdm_FileDescriptor *descPtr;
  185.     int origBlockSize;
  186.     Fscache_Block *blockPtr;
  187.     Boolean    found;
  188.     ReturnStatus    status = SUCCESS;
  189.  
  190.     if (LfsIsNilDiskAddr(diskAddr)) {
  191.     /*
  192.      * The block is not allocated on disk. Do nothing.
  193.      */
  194.     return SUCCESS;
  195.     }
  196.     descPtr = handlePtr->descPtr;
  197.  
  198.     origBlockSize = (descPtr->lastByte + 1) - blockNum * FS_BLOCK_SIZE;
  199.     if (origBlockSize <= 0) {
  200.     LfsError(lfsPtr, FAILURE, "GrowBlock: Bad original size of block\n");
  201.     return FAILURE;
  202.     }
  203.     origBlockSize = LfsBlocksToBytes(lfsPtr, 
  204.                 LfsBytesToBlocks(lfsPtr,origBlockSize));
  205.  
  206.     if (origBlockSize + growthSize > FS_BLOCK_SIZE) {
  207.     LfsError(lfsPtr, FAILURE, "GrowBlock: Bad  size of block\n");
  208.     return FAILURE;
  209.     }
  210.  
  211.     if (descPtr->fileType != FS_DIRECTORY) { 
  212.     /*
  213.      * If the file is not a directory we need to read the block in 
  214.      * and mark it as dirty so it will be written back. This
  215.      * is because the block now too small on disk and we must
  216.      * write it out with its new larger size. The reason why
  217.      * we must fetch the block is that the growth may be due
  218.      * to a write pass the end block of the file.  This causes the
  219.      * old last block to no longer be a fragment. The new bytes in
  220.      * this block must be zeros.  This can not happen for directories
  221.      * because the file system controls writes to directory blocks.
  222.      */
  223.     Fscache_FetchBlock(&handlePtr->cacheInfo, blockNum,
  224.             cacheFlags, &blockPtr, &found);
  225.     if (!found) {
  226.         if (blockPtr == (Fscache_Block *) NIL) {
  227.         status = FS_WOULD_BLOCK;
  228.         return status;
  229.         }
  230.          status = LfsReadBytes(lfsPtr, diskAddr, origBlockSize, 
  231.                blockPtr->blockAddr);
  232.         bzero(blockPtr->blockAddr+origBlockSize, FS_BLOCK_SIZE-origBlockSize);
  233. #ifdef ERROR_CHECK
  234.          LfsCheckRead(lfsPtr, diskAddr, origBlockSize);
  235. #endif
  236.          if (status != SUCCESS) {
  237.          LfsError(lfsPtr, status, "Can't read block to grow.\n");
  238.          return status;
  239.          }
  240.     }
  241.  
  242.     Fscache_UnlockBlock(blockPtr,(unsigned)Fsutil_TimeInSeconds(), 
  243.                 blockNum, origBlockSize+growthSize, 0);
  244.     }
  245.     /*
  246.      * Grow the active bytes of the segment. The activeBytes will
  247.      * be decremented when the file is deleted or the block is written
  248.      * out to disk.
  249.      */
  250.     LfsSetSegUsage(lfsPtr, LfsDiskAddrToSegmentNum(lfsPtr, diskAddr),
  251.             growthSize);
  252.     return status;
  253. }
  254.  
  255. /*
  256.  *----------------------------------------------------------------------
  257.  *
  258.  * AccessBlock --
  259.  *
  260.  *    Access and perform a GET or SET operation on the specified block
  261.  *    of the specified file.
  262.  *
  263.  * Results:
  264.  *    SUCCESS if operation worked ok.
  265.  *    FS_WOULD_BLOCK if operation would block an cantBlock set.
  266.  *
  267.  * Side effects:
  268.  *    Index block may be allocated.
  269.  *
  270.  *----------------------------------------------------------------------
  271.  */
  272.  
  273. static ReturnStatus
  274. AccessBlock(op, lfsPtr, handlePtr, blockNum, blockSize, cacheFlags, 
  275.         diskAddressPtr)
  276.     enum IndexOp           op;         /* Operation to be performed. 
  277.                           * Must be GET_ADDR,  
  278.                           * SET_ADDR or GROW_ADDR. */
  279.     Fsio_FileIOHandle          *handlePtr;    /* Handle for file that are 
  280.                           * interest in. */
  281.     Lfs        *lfsPtr;             /* File system of file. */
  282.     int        blockNum;             /* Block number of file. */
  283.     int        blockSize;        /* Block size for set operation */
  284.     int        cacheFlags;         /* FSCACHE_CANT_BLOCK,FSCACHE_DONT_BLOCK.*/
  285.     LfsDiskAddr *diskAddressPtr;        /* Disk address in/out. */
  286. {
  287.     int parentIndex, parentBlockNum;
  288.     LfsDiskAddr parentDiskAddress;
  289.     Fsdm_FileDescriptor     *descPtr;
  290.     Fscache_Block *parentblockPtr;
  291.     int    modTime;
  292.     Boolean    found;
  293.     ReturnStatus    status;
  294.     LfsDiskAddr *indirectPtr, *directPtr;
  295.  
  296.     descPtr = handlePtr->descPtr;
  297.     directPtr = (LfsDiskAddr *)(descPtr->direct);
  298.     indirectPtr = (LfsDiskAddr *)(descPtr->indirect);
  299.  
  300.     /*
  301.      * First process the data and indirect blocks that are pointed to 
  302.      * by the descriptor.
  303.      */
  304.     if (blockNum < 0) {
  305.     if (op == GROW_ADDR) {
  306.         panic("LfsAccessBlock - Can't grow indirect block\n");
  307.         return FAILURE;
  308.     }
  309.     if (blockNum >= -FSDM_NUM_INDIRECT_BLOCKS) { 
  310.         /*
  311.          * This is a direct indirect block.
  312.          */
  313.         if (op == GET_ADDR) { 
  314.         *diskAddressPtr = indirectPtr[(-blockNum)-1];
  315.         } else { /* SET_ADDR */
  316.         LfsDiskAddr *addrPtr = indirectPtr + ((-blockNum)-1);
  317.         LfsSegUsageFreeBlocks(lfsPtr, blockSize, 1, addrPtr);
  318.         *addrPtr = *diskAddressPtr;
  319.         descPtr->flags |= FSDM_FD_INDEX_DIRTY;
  320.         (void) Fsdm_FileDescStore(handlePtr, FALSE);
  321.         }
  322.         return(SUCCESS);
  323.      }
  324.      if (blockNum > -(FSDM_NUM_INDIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK)) {
  325.          parentIndex = (-blockNum) - (FSDM_NUM_INDIRECT_BLOCKS+1);
  326.          parentBlockNum = -2;
  327.      } else {
  328.         /*
  329.          * Past the largest file size that we support.
  330.          */
  331.         return(FS_INVALID_ARG);
  332.      }
  333.     } else { 
  334.     if (blockNum < FSDM_NUM_DIRECT_BLOCKS) {
  335.         /*
  336.          * This is a direct data block.
  337.          */
  338.         status = SUCCESS;
  339.         switch (op) {
  340.         case GET_ADDR: { 
  341.             *diskAddressPtr = directPtr[blockNum];
  342.             break;
  343.         }
  344.         case SET_ADDR: {
  345.             LfsDiskAddr *addrPtr = (directPtr + blockNum);
  346.             LfsSegUsageFreeBlocks(lfsPtr, blockSize, 1, addrPtr);
  347.             *addrPtr = *diskAddressPtr;
  348.             descPtr->flags |= FSDM_FD_INDEX_DIRTY;
  349.             (void) Fsdm_FileDescStore(handlePtr, FALSE);
  350.             break;
  351.         }
  352.         case GROW_ADDR: {
  353.             status = GrowBlock(lfsPtr, handlePtr, blockNum, 
  354.                 blockSize, directPtr[blockNum], 
  355.                 cacheFlags & 
  356.                    (FSCACHE_CANT_BLOCK|FSCACHE_DONT_BLOCK));
  357.             *diskAddressPtr = directPtr[blockNum];
  358.             break;
  359.         }
  360.         }
  361.         return(status);
  362.     }
  363.     if (blockNum < (FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK)) {
  364.         parentBlockNum = -1;
  365.         parentIndex = blockNum - FSDM_NUM_DIRECT_BLOCKS;
  366.     } else if (blockNum < FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK +
  367.                 FSDM_INDICES_PER_BLOCK*FSDM_INDICES_PER_BLOCK) {
  368.         parentBlockNum = -((FSDM_NUM_INDIRECT_BLOCKS+1) +
  369.           (blockNum - FSDM_NUM_DIRECT_BLOCKS - FSDM_INDICES_PER_BLOCK)/
  370.             FSDM_INDICES_PER_BLOCK);
  371.         parentIndex = (blockNum - FSDM_NUM_DIRECT_BLOCKS - 
  372.                FSDM_INDICES_PER_BLOCK) % FSDM_INDICES_PER_BLOCK;
  373.     } else {
  374.         /*
  375.          * Past the largest file size that we support.
  376.          */
  377.         return(FS_INVALID_ARG);
  378.     }
  379.  
  380.     }
  381.     cacheFlags |= ((op == SET_ADDR) ? 
  382.                   (FSCACHE_IND_BLOCK|FSCACHE_IO_IN_PROGRESS) 
  383.                     : FSCACHE_IND_BLOCK);
  384.  
  385.  
  386.     switch (op) {
  387.     case GET_ADDR: {
  388.         LFS_STATS_INC(lfsPtr->stats.index.getFetchBlock);
  389.         break;
  390.     }
  391.     case SET_ADDR: {
  392.         LFS_STATS_INC(lfsPtr->stats.index.setFetchBlock);
  393.         break;
  394.     } 
  395.     case GROW_ADDR: {
  396.         LFS_STATS_INC(lfsPtr->stats.index.growFetchBlock);
  397.         break;
  398.     } 
  399.     }
  400.      /* 
  401.      * Lookup the parent block in the cache.
  402.      */
  403.    Fscache_FetchBlock(&handlePtr->cacheInfo, parentBlockNum,
  404.         cacheFlags, &parentblockPtr, &found);
  405.     if ((parentblockPtr != (Fscache_Block *) NIL) && found) {
  406.     modTime = 0;
  407.      status = SUCCESS;
  408.      switch (op) {
  409.          case GET_ADDR: {
  410.         LFS_STATS_INC(lfsPtr->stats.index.getFetchHit);
  411.         *diskAddressPtr = 
  412.             ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex];
  413.         break;
  414.          } 
  415.          case SET_ADDR: {
  416.         LfsDiskAddr *addrPtr;
  417.         addrPtr = ((LfsDiskAddr *)parentblockPtr->blockAddr) + 
  418.                parentIndex; 
  419.         LFS_STATS_INC(lfsPtr->stats.index.setFetchHit);
  420.         LfsSegUsageFreeBlocks(lfsPtr, blockSize, 1, addrPtr);
  421.         *addrPtr = *diskAddressPtr;
  422.         modTime = Fsutil_TimeInSeconds();
  423.         break;
  424.          }
  425.          case GROW_ADDR: {
  426.         *diskAddressPtr = 
  427.             ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex];
  428.         status = GrowBlock(lfsPtr, handlePtr, blockNum, 
  429.                 blockSize, *diskAddressPtr, 
  430.                 cacheFlags & 
  431.                    (FSCACHE_CANT_BLOCK|FSCACHE_DONT_BLOCK));
  432.         break;
  433.          } 
  434.      }
  435.      Fscache_UnlockBlock(parentblockPtr, (unsigned )modTime, parentBlockNum,
  436.                  FS_BLOCK_SIZE, 0);
  437.      return status;
  438.     }
  439.     if (parentblockPtr == (Fscache_Block *) NIL) {
  440.     return FS_WOULD_BLOCK;
  441.     }
  442.     /*
  443.      * Not found in cache. Try to read it in. First we need to find the
  444.      * address of the block.
  445.      */
  446.     status = AccessBlock(GET_ADDR, lfsPtr, handlePtr, parentBlockNum, 0,
  447.                 cacheFlags,
  448.                 &parentDiskAddress);
  449.     if (status != SUCCESS) {
  450.      Fscache_UnlockBlock(parentblockPtr, (unsigned )0, parentBlockNum,
  451.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  452.     return status;
  453.     }
  454.     if (LfsIsNilDiskAddr(parentDiskAddress)) {
  455.     switch (op) {
  456.         case GROW_ADDR: 
  457.         case GET_ADDR: {
  458.          LfsSetNilDiskAddr(diskAddressPtr);
  459.          Fscache_UnlockBlock(parentblockPtr, (unsigned)0,
  460.                  parentBlockNum,
  461.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  462.          break;
  463.         }
  464.         case SET_ADDR: {
  465.         register LfsDiskAddr *intPtr, *limitPtr;
  466.         limitPtr = (LfsDiskAddr *) (parentblockPtr->blockAddr + 
  467.                         FS_BLOCK_SIZE);
  468.         for (intPtr = (LfsDiskAddr *)parentblockPtr->blockAddr;
  469.                 intPtr < limitPtr; intPtr++) {
  470.             LfsSetNilDiskAddr(intPtr);
  471.         }
  472.         ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex] = 
  473.                 *diskAddressPtr;
  474.          Fscache_UnlockBlock(parentblockPtr, 
  475.                     (unsigned )Fsutil_TimeInSeconds(),
  476.                     parentBlockNum, FS_BLOCK_SIZE, 0);
  477.          break;
  478.         }
  479.     }
  480.     return SUCCESS;
  481.      }
  482.  
  483.      status = LfsReadBytes(lfsPtr, parentDiskAddress, 
  484.         FS_BLOCK_SIZE,  parentblockPtr->blockAddr);
  485. #ifdef ERROR_CHECK
  486.      LfsCheckRead(lfsPtr, parentDiskAddress, FS_BLOCK_SIZE);
  487. #endif
  488.      if (status != SUCCESS) {
  489.      Fscache_UnlockBlock(parentblockPtr, (unsigned )0, parentBlockNum,
  490.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  491.      LfsError(lfsPtr, status, "Can't read indirect block.\n");
  492.      return status;
  493.      }
  494.      modTime = 0;
  495.      switch (op) {
  496.      case GET_ADDR: {
  497.         *diskAddressPtr =  
  498.             ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex];
  499.         break;
  500.      }
  501.      case SET_ADDR: {
  502.         LfsDiskAddr *addrPtr = ((LfsDiskAddr *)parentblockPtr->blockAddr) + 
  503.                         parentIndex; 
  504.         LfsSegUsageFreeBlocks(lfsPtr, blockSize, 1, addrPtr);
  505.         *addrPtr = *diskAddressPtr;
  506.         modTime = Fsutil_TimeInSeconds();
  507.         break;
  508.      }
  509.      case GROW_ADDR: {
  510.         *diskAddressPtr =  
  511.             ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex];
  512.         status = GrowBlock(lfsPtr, handlePtr, blockNum, 
  513.                 blockSize, *diskAddressPtr, 
  514.                 cacheFlags & 
  515.                    (FSCACHE_CANT_BLOCK|FSCACHE_DONT_BLOCK));
  516.         break;
  517.      }
  518.     }
  519.     Fscache_UnlockBlock(parentblockPtr, (unsigned) modTime, 
  520.                 parentBlockNum, FS_BLOCK_SIZE, 0);
  521.     return(SUCCESS);
  522. }
  523.  
  524. /*
  525.  *----------------------------------------------------------------------
  526.  *
  527.  * DeleteIndirectBlock --
  528.  *
  529.  *    Deallocate and remove from the cache all blocks of the specified
  530.  *    file greater than the given block number.
  531.  *
  532.  * Results:
  533.  *    SUCCESS if all goes well or some error returned from DiskRead
  534.  *
  535.  * Side effects:
  536.  *    None.
  537.  *
  538.  *----------------------------------------------------------------------
  539.  */
  540.  
  541. static ReturnStatus
  542. DeleteIndirectBlock(lfsPtr, handlePtr, virtualBlockNum, diskAddrPtr, 
  543.     startBlockNum, lastBlockNum, step, lastByteBlock) 
  544.     Lfs      *lfsPtr;
  545.     Fsio_FileIOHandle          *handlePtr;    /* Handle for file that are 
  546.                           * interest in. */
  547.     int      virtualBlockNum;    /* Virtual block number for this indirect 
  548.                  * block. */
  549.     LfsDiskAddr      *diskAddrPtr;    /* Disk address of block. */
  550.     int      startBlockNum;    /* Starting block number of this virtual
  551.                  * Block. */
  552.     int      lastBlockNum;        /* New last block number of file. */
  553.     int      step;            /* Number of blocks covered by each virtual
  554.                  * block entry. */
  555.     int      lastByteBlock;    /* Block containing last byte of file. */
  556. {
  557.     Fscache_Block    *cacheBlockPtr;
  558.     LfsDiskAddr        diskAddr = *diskAddrPtr;
  559.     Boolean        found;
  560.     ReturnStatus    status = SUCCESS;
  561.     Boolean        blockInCache;
  562.     int            startElement, cstep, childBlockNum, i;
  563.     LfsDiskAddr    *blockArray;
  564.     /*
  565.      * If this index block hasn't been allocated yet and not in the  
  566.      * cache we still need to check to see if any of its children
  567.      * might be in the cache.  
  568.      */
  569.     LFS_STATS_INC(lfsPtr->stats.index.deleteFetchBlock);
  570.     blockInCache = TRUE;
  571.     Fscache_FetchBlock(&handlePtr->cacheInfo, virtualBlockNum,
  572.        (int)(FSCACHE_IO_IN_PROGRESS|FSCACHE_IND_BLOCK), &cacheBlockPtr,&found);
  573.     if (!found) {
  574.     if (LfsIsNilDiskAddr(diskAddr)) {
  575.         Fscache_UnlockBlock(cacheBlockPtr, (unsigned )0, virtualBlockNum,
  576.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  577.         blockInCache = FALSE;
  578.     } else {
  579.         /*
  580.          * Read it into the cache if it on disk somewhere.
  581.          */
  582.         LFS_STATS_INC(lfsPtr->stats.index.deleteFetchBlockMiss);
  583.         status = LfsReadBytes(lfsPtr, diskAddr, FS_BLOCK_SIZE, 
  584.                cacheBlockPtr->blockAddr);
  585. #ifdef ERROR_CHECK
  586.          LfsCheckRead(lfsPtr, diskAddr, FS_BLOCK_SIZE);
  587. #endif
  588.          if (status != SUCCESS) {
  589.          LfsError(lfsPtr, status, "Can't read indirect block.\n");
  590.          return status;
  591.          }
  592.     }
  593.     }
  594.     /*
  595.      * Compute the starting element of the block to start deleting at.
  596.      * If step equals one we must be pointing to data blocks.
  597.      */
  598.     startElement = (lastBlockNum - startBlockNum)/step;
  599.     if (startElement < 0) {
  600.     startElement = 0;
  601.     } else if (startElement > FSDM_INDICES_PER_BLOCK) {
  602.     panic("Bad call to DeleteIndirectBlock\n");
  603.     }
  604.     if (step != 1) {
  605.     static LfsDiskAddr nilAddr;
  606.     LfsDiskAddr *addrPtr = &nilAddr;
  607.     cstep = step/FSDM_INDICES_PER_BLOCK;
  608.     startBlockNum = startBlockNum + startElement * step;
  609.     childBlockNum = -((FSDM_NUM_INDIRECT_BLOCKS+1)+startElement);
  610.     LfsSetNilDiskAddr(addrPtr);
  611.     for (i = startElement; i < FSDM_INDICES_PER_BLOCK; i++) { 
  612.         if (blockInCache) { 
  613.         addrPtr = ((LfsDiskAddr *) cacheBlockPtr->blockAddr) + i;
  614.         } 
  615.         status = DeleteIndirectBlock(lfsPtr, handlePtr, childBlockNum, 
  616.                 addrPtr, startBlockNum, lastBlockNum, cstep, 
  617.                 lastByteBlock);
  618.         startBlockNum += step;
  619.         childBlockNum--;
  620.     }
  621.     } else if (blockInCache) {
  622.     blockArray =  ((LfsDiskAddr *) cacheBlockPtr->blockAddr) + startElement;
  623.     /*
  624.      * Free the last block in the file handling the case that it
  625.      * is a fragment.
  626.      */
  627.     if ((lastByteBlock >= startBlockNum) && 
  628.         (lastByteBlock < startBlockNum + FSDM_INDICES_PER_BLOCK) &&
  629.         (lastByteBlock >= lastBlockNum)) {
  630.         int fragSize;
  631.         fragSize = handlePtr->descPtr->lastByte - 
  632.                 (lastByteBlock * FS_BLOCK_SIZE) + 1;
  633.         fragSize = LfsBlocksToBytes(lfsPtr, LfsBytesToBlocks(lfsPtr, 
  634.                             fragSize));
  635.  
  636.         (void) LfsSegUsageFreeBlocks(lfsPtr, fragSize, 1,
  637.             blockArray + (lastByteBlock - startBlockNum));
  638.     }
  639.     (void) LfsSegUsageFreeBlocks(lfsPtr, FS_BLOCK_SIZE, 
  640.             FSDM_INDICES_PER_BLOCK - startElement, blockArray);
  641.     }
  642.     if (blockInCache) { 
  643.     /*
  644.      * If we deleted all the indexes in this block we can delete the block.
  645.      */
  646.     if (startElement == 0) {
  647.         Fscache_UnlockBlock(cacheBlockPtr, (unsigned )0, virtualBlockNum,
  648.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  649.         (void) LfsSegUsageFreeBlocks(lfsPtr, FS_BLOCK_SIZE, 1, diskAddrPtr);
  650.     } else {
  651.         Fscache_UnlockBlock(cacheBlockPtr,(unsigned)Fsutil_TimeInSeconds(), 
  652.                 virtualBlockNum, FS_BLOCK_SIZE, 0);
  653.     }
  654.     }
  655.     return status;
  656. }
  657.  
  658. /*
  659.  *----------------------------------------------------------------------
  660.  *
  661.  * LfsFile_TruncIndex --
  662.  *
  663.  *    Truncate the index of the specified file to only be the specified
  664.  *    number of blocks in length.
  665.  *
  666.  * Results:
  667.  *    SUCCESS if all goes well, a return status otherwise.
  668.  *
  669.  * Side effects:
  670.  *    None.
  671.  *
  672.  *----------------------------------------------------------------------
  673.  */
  674. ReturnStatus 
  675. LfsFile_TruncIndex(lfsPtr, handlePtr, length)
  676.     Lfs                *lfsPtr;
  677.     Fsio_FileIOHandle    *handlePtr;    /* Handle for file that are 
  678.                      * interest in. */
  679.     int             length;      /* Number of bytes to 
  680.                       * leave in file. */
  681. {
  682.     Fsdm_FileDescriptor    *descPtr;
  683.     ReturnStatus    status = SUCCESS;
  684.     int            lastByteBlock, fragSize;
  685.     int            numBlocks;
  686.  
  687.     LFS_STATS_INC(lfsPtr->stats.index.truncs);
  688.     numBlocks = (length + (FS_BLOCK_SIZE-1))/FS_BLOCK_SIZE;
  689.     descPtr = handlePtr->descPtr;
  690.     lastByteBlock = descPtr->lastByte/FS_BLOCK_SIZE;
  691.  
  692.  
  693.     /*
  694.      * Delete any DBL_INDIRECT blocks left over from this truncate. This is
  695.      * necessary only if the old length had double indirect blocks.
  696.      */
  697.     if ((numBlocks < (FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK +
  698.              FSDM_INDICES_PER_BLOCK * FSDM_INDICES_PER_BLOCK)) &&
  699.     (lastByteBlock >= (FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK))) {
  700.     status = DeleteIndirectBlock(lfsPtr, handlePtr, -2, 
  701.             &(descPtr->indirect[1]),
  702.             FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK,
  703.             numBlocks, FSDM_INDICES_PER_BLOCK, lastByteBlock);
  704.     }
  705.     /*
  706.      * Followed by any INDIRECT blocks if the old length had
  707.      * indirect blocks.
  708.      */
  709.     if ((numBlocks < (FSDM_INDICES_PER_BLOCK + FSDM_NUM_DIRECT_BLOCKS)) &&
  710.         (lastByteBlock >= FSDM_NUM_DIRECT_BLOCKS)) {
  711.     status = DeleteIndirectBlock(lfsPtr, handlePtr, -1, 
  712.             &(descPtr->indirect[0]),
  713.             FSDM_NUM_DIRECT_BLOCKS, numBlocks, 1, lastByteBlock);
  714.     }
  715.     /*
  716.      * Finally the DIRECT blocks.
  717.      */
  718.     if (numBlocks < FSDM_NUM_DIRECT_BLOCKS) {
  719.     /*
  720.      * The last block in the file may be a fragement. Free it first.
  721.      */
  722.     if ((descPtr->lastByte >= 0) &&
  723.         (lastByteBlock < FSDM_NUM_DIRECT_BLOCKS) && 
  724.         (lastByteBlock >= numBlocks)) {
  725.         /*
  726.          * Compute the size of the fragment and round it into lfs
  727.          * blocks.
  728.          */
  729.         fragSize = descPtr->lastByte - (lastByteBlock * FS_BLOCK_SIZE) + 1;
  730.         /*
  731.          * Round to the number of LFS blocks it would take.
  732.          */
  733.         fragSize = LfsBlocksToBytes(lfsPtr, 
  734.                 LfsBytesToBlocks(lfsPtr, fragSize));
  735.         (void) LfsSegUsageFreeBlocks(lfsPtr, fragSize, 1, 
  736.             ((LfsDiskAddr *)descPtr->direct) + lastByteBlock);
  737.     }
  738.     (void) LfsSegUsageFreeBlocks(lfsPtr, FS_BLOCK_SIZE, 
  739.             FSDM_NUM_DIRECT_BLOCKS - numBlocks,    
  740.             ((LfsDiskAddr *)descPtr->direct) + numBlocks);
  741.     }
  742.  
  743.     return status;
  744. }
  745.  
  746.  
  747. /*
  748.  *----------------------------------------------------------------------
  749.  *
  750.  * LfsFile_GrowBlock --
  751.  *
  752.  *    Grow the specified block of the specified file.
  753.  *
  754.  * Results:
  755.  *    A status indicating whether there was sufficient space to allocate
  756.  *    block
  757.  *
  758.  * Side effects:
  759.  *
  760.  *----------------------------------------------------------------------
  761.  */
  762.  
  763. ReturnStatus
  764. LfsFile_GrowBlock(lfsPtr, handlePtr, offset, numBytes)
  765.     Lfs                *lfsPtr;
  766.     Fsio_FileIOHandle    *handlePtr;   /* Handle for file that are 
  767.                        * interest in. */
  768.     int        offset;             /* Offset to allocate at. */
  769.     int        numBytes;         /* Number of bytes to make block. */
  770. {
  771.     ReturnStatus        status;
  772.     int    newLastByte,  blockNum;
  773.     register    Fsdm_FileDescriptor *descPtr;
  774.     LfsDiskAddr diskAddress;
  775.     int     oldSize, oldLastBlock;
  776.  
  777.  
  778.     /*
  779.      * Process the common case that we are appending to the end of the file
  780.      * starting at a block boundry.  We know the block can't already exist
  781.      * so we don't need to grow it. 
  782.      */
  783.     descPtr = handlePtr->descPtr;
  784.     oldSize = descPtr->lastByte + 1;
  785.     LFS_STATS_INC(lfsPtr->stats.blockio.fastAllocs);
  786.     if ((offset % FS_BLOCK_SIZE == 0) && (offset == oldSize)) {
  787.     return LfsSegUsageAllocateBytes(lfsPtr, numBytes);
  788.     }
  789.     newLastByte = offset + numBytes - 1;
  790.     blockNum = offset / FS_BLOCK_SIZE;
  791.     oldLastBlock = oldSize / FS_BLOCK_SIZE;
  792.     if (newLastByte > descPtr->lastByte) {
  793.     int blocksToGrow, bytesToGrow, lastFragSize, extraBytes;
  794.     /*
  795.      * We are writing passed the end of the file. If the last block is 
  796.      * a fragment we must grow it.
  797.      */
  798.     lastFragSize = oldSize % FS_BLOCK_SIZE;
  799.     if (lastFragSize > 0) { 
  800.         int newLastFragSize;
  801.         newLastFragSize = lastFragSize + (newLastByte - descPtr->lastByte);
  802.         if (newLastFragSize > FS_BLOCK_SIZE) {
  803.         newLastFragSize = FS_BLOCK_SIZE;
  804.         }
  805.         blocksToGrow = LfsBytesToBlocks(lfsPtr, newLastFragSize) - 
  806.                 LfsBytesToBlocks(lfsPtr, lastFragSize);
  807.     } else {
  808.         /*
  809.          * The last block in the file was not a fragment. No need to
  810.          * grow it.
  811.          */
  812.         blocksToGrow = 0;
  813.     }
  814.     if (blocksToGrow > 0) {
  815.         bytesToGrow = LfsBlocksToBytes(lfsPtr,blocksToGrow);
  816.         /*
  817.          * Allocate and grow the last block of the file. At the same
  818.          * time we can allocate space if a new last block is being 
  819.          * created.
  820.          */
  821.         extraBytes = (oldLastBlock == blockNum) ? 0 : numBytes;
  822.         status = LfsSegUsageAllocateBytes(lfsPtr, bytesToGrow + extraBytes);
  823.         if (status == SUCCESS) {
  824.          /* If this block is already allocated to disk and we are 
  825.           * growing it, increment the segment usage count to reflect 
  826.           * the larger block size so it will be correctly freed 
  827.           * when it is overwritten or deleted. 
  828.           */
  829.         LFS_STATS_INC(lfsPtr->stats.blockio.slowAllocs);
  830.         status = AccessBlock(GROW_ADDR, lfsPtr, handlePtr, 
  831.                   oldLastBlock, bytesToGrow, 0, &diskAddress);
  832.         } 
  833.     } else if (oldLastBlock != blockNum) {
  834.         /*
  835.          * The last block of the file doesn't need to be grown any but
  836.          * the write is creating a new last block that we must allocate
  837.          * space for.
  838.          */
  839.         status = LfsSegUsageAllocateBytes(lfsPtr, numBytes);
  840.     } else {
  841.         /*
  842.          * The write is to the last block of the file but doesn't cause
  843.          * the file to take any more space on disk because space is 
  844.          * rounded to block sizes.
  845.          */
  846.         status = SUCCESS;
  847.     }
  848.     } else {
  849.     /*
  850.      * We are writing into the middle of the file. Check to see if 
  851.      * the block previous existed. We can skip this check if we
  852.      * know that the file system has enough room for this block.
  853.      */
  854.     LFS_STATS_INC(lfsPtr->stats.blockio.fastAllocs);
  855.     status = LfsSegUsageAllocateBytes(lfsPtr, numBytes);
  856.     if (status != SUCCESS) { 
  857.         LFS_STATS_INC(lfsPtr->stats.blockio.slowAllocs);
  858.         status = AccessBlock(GET_ADDR, lfsPtr, handlePtr, blockNum, 
  859.                 FS_BLOCK_SIZE, 0, &diskAddress);
  860.         if ((status != SUCCESS) || LfsIsNilDiskAddr(diskAddress)) {
  861.         LFS_STATS_INC(lfsPtr->stats.blockio.slowAllocFails);
  862.         status = FS_NO_DISK_SPACE;
  863.         }
  864.     }
  865.  
  866.     }
  867.  
  868.     return status;
  869. }
  870.  
  871.